
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

public class Parser extends DefaultHandler {

	ArrayList<DocumentEntity> xmlDocs;

	private String tempVal;
	private static ArrayList<String> classList;
	private StringBuffer tempValBuf = new StringBuffer();
	private StringBuffer tempV = new StringBuffer();
	private String docName;
	private int trainingSetSize = 0;
	

	private static HashMap<String, ClassDetails> classInfoMap;

	// to maintain context
	public DocumentEntity tempDoc;
	Document dom;

	public Parser() {
		xmlDocs = new ArrayList<DocumentEntity>();
	}

	public ParsedResult parseXmlFile(String path,
			HashMap<String, ClassDetails> classInfoMap) {
		// get the factory
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		this.classInfoMap = classInfoMap;
		try {

			// Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();

			// parse using builder to get DOM representation of the XML file
			// parse the file and also register this class for call backs
			// read the documents of the training set
			File trainingSetPath = new File(path);

			File[] files = trainingSetPath.listFiles();

			for (int i = 0; i < files.length; i++) {
				if (files[i].isFile()) {
					docName = files[i].toString();
					// parse the file
					dom = db.parse(docName);

				}
			}

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		} catch (SAXException se) {
			se.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}

		parseDocument();
		trainingSetSize = xmlDocs.size();
		System.out.println("Training size:---------------" + trainingSetSize);
		
		return new ParsedResult(classInfoMap, trainingSetSize);
	}

	private void parseDocument() {
		// get the root elememt
		Element docEle = dom.getDocumentElement();

		// get a nodelist of <Reuters> elements
		NodeList nl = docEle.getElementsByTagName("REUTERS");
/*		System.out.println("nl.getLength():" + nl.getLength());*/
		if (nl != null && nl.getLength() > 0) {
			for (int i = 0; i < nl.getLength(); i++) {

				// get the Reuters element
				Element el = (Element) nl.item(i);

				// get the document object
				DocumentEntity doc = getDocument(el);

				// add it to list
				xmlDocs.add(doc);
				
				ArrayList<String> docClassList = doc.getClassList();
				
				Iterator<String> dcItr = docClassList.iterator();

				while (dcItr.hasNext()) {
					String currentClass = dcItr.next();
					
					System.out.println("Current class in while:"+currentClass);
					
					if (classInfoMap.containsKey(currentClass))
					{
						ClassDetails classDetails = classInfoMap.get(currentClass);
						if (classDetails == null)
							classDetails = new ClassDetails();
						ArrayList<DocumentEntity> docList = classDetails.getDocList();
						if (docList == null)
						{
							docList = new ArrayList<DocumentEntity>();
							//classDetails.setDocList(docList); 
							classInfoMap.put(currentClass, classDetails);
						}
						//docList.add(tempDoc.getID());
						
						docList.add(doc);
						classInfoMap.put(currentClass, classDetails);
						
						
					}
				}		
				

			}
		}
	}

	private DocumentEntity getDocument(Element docEl) {
		classList = new ArrayList<String>();
		String body = "", title = "";
		// for each <REUTERS> element get text or int values of
		// Topics ,Places, People etc.

		int docID = Integer.parseInt(docEl.getAttribute("NEWID"));
		
		ArrayList<String> topic = getTextValue(docEl, "TOPICS");
		
		Iterator<String> topicItr = topic.iterator();

		while (topicItr.hasNext()) {
			String currentClass = topicItr.next();
			classList.add(currentClass);
		}
		
		/*System.out.println("topic:" + topic.toString());*/

		/*
		 * ArrayList<String> dTagValueList = getTextValue(docEl, "D"); //String
		 * dTagValueStr = dTagValueList.toString();
		 * System.out.println("dTagValueList:" + dTagValueList.toString());
		 */

		ArrayList<String> place = getTextValue(docEl, "PLACES");
		
		Iterator<String> placeItr = place.iterator();

		while (placeItr.hasNext()) {
			String currentClass = placeItr.next();
			classList.add(currentClass);
		}
		System.out.println("place:" + place.toString());
		
		ArrayList<String> people = getTextValue(docEl, "PEOPLE");
		Iterator<String> peopleItr = people.iterator();
		while (peopleItr.hasNext()) {
			String currentClass = peopleItr.next();
			classList.add(currentClass);
		}
		
		System.out.println("people:" + people.toString());

		ArrayList<String> org = getTextValue(docEl, "ORGS");
		Iterator<String> orgItr = org.iterator();
		while (orgItr.hasNext()) {
			String currentClass = orgItr.next();
			classList.add(currentClass);
		}

		ArrayList<String> exchange = getTextValue(docEl, "EXCHANGES");
		Iterator<String> exchangeItr = exchange.iterator();
		while (exchangeItr.hasNext()) {
			String currentClass = exchangeItr.next();
			classList.add(currentClass);
		}
		System.out.println("exchange:" + exchange.toString());

		ArrayList<String> titleTemp = getTextValue(docEl, "TITLE");
		/*System.out.println("title:" + title.toString());*/
		Iterator<String> titleItr = titleTemp.iterator();
		if (titleItr.hasNext()) {
			title = titleItr.next();
		}

		ArrayList<String> bodyList = getTextValue(docEl, "BODY");
		
		Iterator<String> bodyItr = bodyList.iterator();
		if (bodyItr.hasNext()) {
			body = bodyItr.next();
		}
		/*System.out.println("body:" + body);*/
		
		System.out.println("class List:"+classList.toString());
	
		DocumentEntity d = new DocumentEntity(classList, title,body, docID);

		return d;
	}

	public void runExample() {
		
		String className;
		String path = "C:/Workspace_Fall2011/TextClassifier/TrainingSet";
		String classNamesSource = "C:/Workspace_Fall2011/TextClassifier/Training/all-classes-strings.lc.txt";
		// initialize the names of classes as keys into the hashmap classInfoMap
		// from the text files having the classnames
		FileReader classNamesFile = null;

		try {
			classNamesFile = new FileReader(classNamesSource);

			BufferedReader br_cnFile = new BufferedReader(classNamesFile);

			while ((className = br_cnFile.readLine()) != null) {
				System.out.println("className in file:"+className);
				if (classInfoMap == null)
					classInfoMap = new HashMap<String, ClassDetails>();
					
					classInfoMap.put(className, null);
			}
		}
		catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		// parse the xml file and get the dom object
		ParsedResult result = parseXmlFile(path, classInfoMap);
		classInfoMap = result.getClassInfoMap();
		int trainingSz = result.getTrainingSetSize();
		
		System.out.println("classInfoMap:");
		
		ClassDetails cd;
		
		Set<Map.Entry<String, ClassDetails>> set = classInfoMap.entrySet();
		
		//iterate over the entire hashmap containing all details of all classes
		for (Map.Entry<String, ClassDetails> me : set) {
			cd = new ClassDetails();
			cd = me.getValue();
			String currentClass = me.getKey();
			System.out.println("=============================");
			System.out.println("Current class:" + currentClass);
			System.out.println("Doclist details:"+cd.getDocList());
		}
		System.out.println();
		System.out.println("training sz::::"+trainingSz);
		
	
		/*parseDocument();*/

		// Iterate through the list and print the data
		printData();

	}

	/**
	 * Iterate through the list and print the contents
	 */
	public void printData() {

		System.out.println("No of Documents '" + xmlDocs.size() + "'.");

		Iterator<DocumentEntity> it = xmlDocs.iterator();
		while (it.hasNext()) {
			System.out.println(it.next().toString());
		}
	}

	private ArrayList<String> getTextValue(Element ele, String tagName) {
		StringBuffer tempBuf = new StringBuffer();
		ArrayList<String> strArrList = new ArrayList<String>();
		ArrayList<String> tempHolder = new ArrayList<String>();
		/*System.out.println("tag name:" + tagName);*/
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		/* System.out.println("Nodelist:"+nl.toString()); */

		if (nl != null && nl.getLength() > 0) {

			/* System.out.println("nl.getLength()......" + nl.getLength()); */

			for (int i = 0; i < nl.getLength(); i++) {
				Node nNode = nl.item(i);

				if (nNode.getNodeType() == Node.ELEMENT_NODE) {

					Element eElement = (Element) nNode;

					if (tagName != "TITLE" && tagName != "BODY") {
						/*
						 * System.out.println("D : " + getTagValue("D",
						 * eElement));
						 */
						strArrList = getTagValue("D", eElement);

						System.out.println("strArrList for tags :" + strArrList);
					} else {
						Element el = (Element) nl.item(i);
						if (el.hasChildNodes()) {
							textVal = el.getFirstChild().getNodeValue();
							strArrList.add(textVal);
						}
					}

				}

			}
		}
		/*System.out.println("textVal returned:" + strArrList.toString());*/
		return strArrList;
	}

	private static ArrayList<String> getTagValue(String sTag, Element eElement) {
		ArrayList<String> strArrList = new ArrayList<String>();
		String textVal = null;

		NodeList nlList = eElement.getElementsByTagName(sTag);
		if (nlList != null && nlList.getLength() > 0) {
			for (int i = 0; i < nlList.getLength(); i++) {

				Element el = (Element) nlList.item(i);
				if (el.hasChildNodes()) {
					textVal = el.getFirstChild().getNodeValue();
					/*System.out.println("TextVal in getTagValue :" + textVal);*/
					strArrList.add(textVal);
				}

			}
		}
		return strArrList;
	}

	

	public static void main(String[] args) {
		// create an instance
		Parser cop = new Parser();

		// call run example
		cop.runExample();
	}
}
